/**
 * Main.java
 *
 * Created on 7 December, 2008, 12:25 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package vrp;

import java.io.FileNotFoundException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;

/**
 * Main program solving a given VRP problem
 * @author Pranay
 */
public class Uts {

    public Uts() {
    }

    /**
     * @param args the command line arguments
     * Usage : 
     *  1) -r instance_file max_iterations_number
     *          > Generate files with the found solution and iterations data
     *          > e.g "-r ./doc/instances/E101-08e.vrp 1000"
     *  2) -z instance_file solution_file
     *          > Gives many information related to the given solution (length, cost ...)  
     *          > e.g "-z ./doc/instances/E101-08e.vrp solution.res"
     */
    public static void main(String[] args) {
        Uts u = new Uts();
        if (args.length != 3) {
            u.prUsage();
        }

        try {
            if (args[0].equals("-r")) {
                u.findSolution(args[1], new Integer(args[2]));
            } else if (args[0].equals("-z")) {
                u.analyzeSolution(args[1], args[2]);
            } else {
                throw new NotImplementedException();
            }
        } catch (Exception e) {
            u.prUsage();
        }
    }

    /**
     * Find a solution for the given problem and write different files
     * > solution.res : containing the best solution found
     * > obj.res : gnuplot file containing each iteration's current solution's length
     * > bobj.res : gnuplot file containing each iteration's best solution's length
     * > temps.res : containig the user execution time in seconds
     * @param instanceFile file containing problem description
     * @param maxIterNum maximum iterations number to use in the algorithm
     */
    public void findSolution(String instanceFile, int maxIterNum) {
    	Constants.MaxIters = maxIterNum;
        FilesManager fm = new FilesManager();
        try {
        	long tStart = System.currentTimeMillis();
	    	// Load the problem
	        Map<Integer, Customer> customers = fm.parseInstanceFile(instanceFile);
	        // Create initial solution
	        Solution initSol = this.createInitialSolution(customers);
	        try {
		        // Launch the algorithm
	        	Tabu algorithm = new Tabu();
	        	Solution finalSol = algorithm.optimizeSolution(initSol);
		        // Write output files
		        double tExec = (double)(System.currentTimeMillis() - tStart)/1000;
		        fm.writeOutputFiles(finalSol, tExec, algorithm.getCurrentSolutionsLength(), algorithm.getBestSolutionsLength());
		        fm.writeDebugFiles(algorithm.getAlphaEvolution(), algorithm.getQEvolution());
		        System.out.println("Solution of length "+finalSol.getLength()+" found in "+tExec+"sec");
		        System.out.println("Output files written ... enjoy your trip !");
	        } catch (Exception ex) {
	            System.out.println("An error occured when trying to solve the problem. Check the algorithm !");
	            System.out.println("Error : "+ex.getMessage());
	        	ex.printStackTrace();
	            System.exit(-1);
	        }
        } catch (FileNotFoundException ex) {
            System.out.println("Instance file not found. Check the given path.");
            System.exit(-1);
        } catch (Exception ex) {
            System.out.println("An error occured when trying to parse the instance file. Check the file format.");
            System.out.println("Error : "+ex.getMessage());
        	ex.printStackTrace();
            System.exit(-1);
        }
        
    }
    
    /**
     * Read the given problem definition file, and the given solution file.
     * That method recalculate the solution length, each round length and usage.
     * No values are returned because they are written in the "fsolution.res" file
     * @param instanceFile File containing the problem definition
     * @param solutionFile File containing a solution to the problem (the one we have to analyze)
     */
    public void analyzeSolution(String instanceFile, String solutionFile) {
    	FilesManager fm = new FilesManager();
        try {
	        Map<Integer, Customer> customers = fm.parseInstanceFile(instanceFile);
	        Solution givenSol = fm.createSolutionFromFile(solutionFile,customers);
	        // Write the fsolution file without doing anything ... values are already populated
	        fm.writeFSolutionFile("fsolution.res", givenSol);
	        System.out.println("Solution analyzed : output files written ... enjoy !");
        } catch (FileNotFoundException ex) {
            System.out.println("Instance file not found. Check the given path.");
            System.exit(-1);
        } catch (Exception ex) {
            System.out.println("An error occured when trying to parse the instance or solution file. Check files format.");
            System.exit(-1);
        }
    }

    /**
     * Creates an initial solution from a Map of customers
     * > Order the customers by their angle and create a round by choosing them by range
     * @param customers Unordered list of customers
     * @return Initial solution associated
     */
    public Solution createInitialSolution(Map<Integer,Customer> customers){
        Solution resu = new Solution();
        // Order customers by their "angle" from the depot
        LinkedList<Customer> cust = new LinkedList<Customer>(customers.values());
        Collections.sort(cust);
        // Create and populate vehicles
        Vehicle currVehicle = new Vehicle();
        resu.setFirstVehicle(currVehicle);
        resu.setNumVehicles(1);
        for(Customer currCustomer : cust){
        	// Skip the depot
        	if(currCustomer == Constants.depot){continue;}
        	if(currVehicle.overflow(currCustomer.getReq()) != 0){
        		// We reached the maximum capacity for the current vehicle and have to add a new one to the solution
        		resu.setLength(resu.getLength() + currVehicle.getLength());
        		resu.setCost(resu.getCost() + currVehicle.getLength());
        		
        		// TODO Refactor this part of code by adding new methods in Vehicle
        		currVehicle.setNextCar(new Vehicle());
        		currVehicle.getNextCar().setPrevCar(currVehicle);
        		resu.setNumVehicles(resu.getNumVehicles() + 1);
        		currVehicle = currVehicle.getNextCar();
        		currVehicle.setId(currVehicle.getPrevCar().getId()+1);
        	}

        	currVehicle.addLastCustomer(currCustomer);
        }
        return resu;
    }
    
    /**
     * Prints program usage to the user
     *
     */
    public void prUsage() {
        System.out.println("********* Bad program usage *********");
        System.out.println("Uts program usage :");
        System.out.println("1) -r instance_file max_iterations_number");
        System.out.println("> Generate files with the found solution ad iterations data");
        System.out.println("2) -r instance_file solution_file");
        System.out.println("> Gives many information related to the given solution (length, cost ...)");
        System.exit(-1);
    }
}